package data.stock;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;

/**
 * The NewsCorpus class contains a sorted set of many news items,
 * accesible by several temporal utility methods
 * @author Kevin Dolan
 */
public class NewsCorpus implements Serializable {

	private static final long serialVersionUID = -4258426190147408868L;
	private TreeMap<Long, List<NewsStory>> news;
	private int count;
	private transient HashMap<Integer, NewsStory> idMap;
	
	public NewsCorpus() {
		news = new TreeMap<Long,List<NewsStory>>();
		idMap = new HashMap<Integer, NewsStory>();
	}
	
	/**
	 * Add a piece of news to the ticker history
	 * @param story the news story object to add
	 */
	public void addNews(NewsStory story) {
		story.setId(count);
		idMap.put(count, story);
		
		List<NewsStory> list = news.get(story.getTime());
		if(list == null) {
			list = new ArrayList<NewsStory>();
			news.put(story.getTime(), list);
		}
		list.add(story);
		count++;
	}
	
	/**
	 * @return the number of news events contained in this set
	 */
	public int getCount() {
		return count;
	}
	
	/**
	 * Get a list of all news stories in a given time range
	 * @param firstTime the beginning of the time range
	 * @param lastTime	the end of the time range
	 * @return			the list of news events
	 */
	public List<NewsStory> getNews(long firstTime, long lastTime) {
		Collection<List<NewsStory>> collection = 
			(news.subMap(firstTime, true, lastTime,true)).values();
		List<NewsStory> list = new ArrayList<NewsStory>();
		for(List<NewsStory> entry : collection)
			for(NewsStory event : entry)
				list.add(event);
		return list;
	}
	
	/**
	 * @return the first time of the news data set
	 */
	public long getFirstNews() {
		return news.firstKey();
	}
	
	/**
	 * @return the last time of the news data set
	 */
	public long getLastNews() {
		return news.lastKey();
	}
	
	/**
	 * @return a list of all news stories in the data set
	 */
	public List<NewsStory> getNews() {
		return getNews(getFirstNews(), getLastNews());
	}
	
	/**
	 * Get a news story by its id
	 * @param id the id to lookup
	 * @return   the news story with that id
	 */
	public NewsStory getNews(int id) {
		if(idMap == null) {
			idMap = new HashMap<Integer, NewsStory>();
			int i = 0;
			for(List<NewsStory> stories : news.values()) {
				for(NewsStory story : stories) {
					idMap.put(i, story);
					story.setId(i);
					i++;
				}
			}
		}
		
		return idMap.get(id);
	}
	
	/**
	 * Get a subset of this news corpus
	 * @param start the beginning of the time range, inclusive
	 * @param end   the end of the time range, inclusive
	 * @return		the subset of news stories in the range
	 */
	public NewsCorpus getSubCorpus(long start, long end) {
		TreeMap<Long, List<NewsStory>> subMap = (TreeMap<Long, List<NewsStory>>) news.subMap(start, true, end, true);
		NewsCorpus subCorpus = new NewsCorpus();
		Collection<List<NewsStory>> storyLists = subMap.values();
		for(List<NewsStory> storyList : storyLists)
			for(NewsStory story : storyList)
				subCorpus.addNews(story.clone());
		return subCorpus;
	}
}